package com.ly.base.chapter04;



import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

/**
 * 统计分析 a
 */
//todo 重点需要去看，很好的复习案例
public class AnalysisDemo {
    private static final String DATA_URL = "D:\\heimaWenJian\\学习笔记\\函数式编程（Stream API）\\Funcation\\LearningBase\\data.txt";
    /*
    数据格式
    0       1       2       3       4       5       6     7      8        9     10    11
    序号    下单时间  订单编号  商品编号 类别编号  类别码   品牌   价格   用户编号   年龄   性别   地区
 */
    static final int INDEX = 0;
    static final int TIME = 1;
    static final int ORDER_ID = 2;
    static final int PRODUCT_ID = 3;
    static final int CATEGORY_ID = 4;
    static final int CATEGORY_CODE = 5;
    static final int BRAND = 6;
    static final int PRICE = 7;
    static final int USER_ID = 8;
    static final int USER_AGE = 9;
    static final int USER_SEX = 10;
    static final int USER_REGION = 11;
    static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
    public static void main(String[] args) {
        case8();
    }

    // 8) 不同年龄段 女性 所下 不同类别 订单
    //方法：获取各年龄段字符串
    static String ageRange(String[] array){
        int age = Double.valueOf(array[USER_AGE]).intValue();
        if (age < 18)return "[0,18)";
        else if ( age < 30)return "[18,30)";
        else if (age < 50)return "[30,50)";
        else return "[50,∞)";
    }
    private static void case8(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<String, TreeMap<String, Long>> map = lines.skip(1)
                    .map(line -> line.split(","))
                    .filter(array -> array[USER_SEX].equals("女"))
                    .filter(array -> !array[CATEGORY_CODE].isEmpty())
                    .collect(groupingBy(AnalysisDemo::ageRange,
                            groupingBy(AnalysisDemo::firstCategory, TreeMap::new, counting())));

            for (Map.Entry<String, TreeMap<String, Long>> e1 : map.entrySet()) {
                for (Map.Entry<String, Long> e2 : e1.getValue().entrySet()) {
                    System.out.printf("%-12s%-15s%s%n",e1.getKey(),e2.getKey(),e2.getValue());
                }
            }

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 7) 按价格区间统计销量
    //方法：返回价格区间字符串
    static String priceRange(Double price){
        if (price < 100)return "[0,100)";
        else if (price >= 100 && price < 500)return "[100,500)";
        else if (price >= 500 && price < 1000)return "[500,1000)";
        else return "[1000,∞)";
    }
    private static void case7(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<String, Long> collect = lines.skip(1)
                    .map(line -> line.split(","))
                    .map(array -> Double.valueOf(array[PRICE]))
                    .collect(groupingBy(AnalysisDemo::priceRange, counting()));

            for (Map.Entry<String, Long> e : collect.entrySet()) {
                System.out.println(e);
            }

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 6.1) 按类别统计销量
    private static void case61(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<String, Long> collect = lines.skip(1)
                    .map(line -> line.split(","))
                    .filter(array -> !array[CATEGORY_CODE].isEmpty())
                    .collect(groupingBy(array -> array[CATEGORY_CODE], TreeMap::new,counting()));

            for (Map.Entry<String, Long> e : collect.entrySet()) {
                System.out.println(e);
            }

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 6.2) 按一级类别统计销量
    //静态方法引用，截取一级类别
    static String firstCategory(String[] array){
        String c = array[CATEGORY_CODE];
        int idx = c.indexOf(".");
        return c.substring(0,idx);
    }
    private static void case62(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<String, Long> collect = lines.skip(1)
                    .map(line -> line.split(","))
                    .filter(array -> !array[CATEGORY_CODE].isEmpty())
                    .collect(groupingBy(AnalysisDemo::firstCategory, TreeMap::new,counting()));

            for (Map.Entry<String, Long> e : collect.entrySet()) {
                System.out.println(e);
            }

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 5.1） 每个地区下单最多的用户
    private static void case51(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<String, Map<String, Long>> collect = lines.skip(1)
                    .map(line -> line.split(","))
                    .collect(groupingBy(array -> array[USER_REGION], groupingBy(array -> array[USER_ID], counting())));
            collect.entrySet().stream()
                    .map(e -> Map.entry(
                            e.getKey(),
                            e.getValue().entrySet().stream().max(Map.Entry.comparingByValue()) //只保留最大值
                    ))
                    .forEach(System.out::println);
            /*for (Map.Entry<String, Map<String, Long>> e1 : collect.entrySet()) {
                System.out.println(e1.getKey());
                System.out.println("---------------");
                int i = 0;
                for (Map.Entry<String, Long> e2 : e1.getValue().entrySet()) {
                    if (i > 5)break;
                    System.out.println(e2);
                    i++;
                }
            }*/

            /** 上海              ---> 上海
             *  1  5             ---> 2  10   //只保留最大值
             *  2  10
             *  3  3
             *
             *  广东 ---> 广东
             *  ...
             */

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 5.2) 每个地区下单最多的前三用户 --------- 排序
    private static void case52(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<String, Map<String, Long>> collect = lines.skip(1)
                    .map(line -> line.split(","))
                    .collect(groupingBy(array -> array[USER_REGION], groupingBy(array -> array[USER_ID], counting())));

            collect.entrySet().stream()
                    .map(e -> Map.entry(
                            e.getKey(),
                            //获取前三的值
                            e.getValue().entrySet().stream()
                                    .sorted(Map.Entry.<String,Long>comparingByValue().reversed())
                                    .limit(3)
                                    .collect(toList())
                    ))
                    .forEach(System.out::println);

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 5.3) 每个地区下单最多的前三用户 --------- 小顶堆
    private static void case53(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<String, Map<String, Long>> collect = lines.skip(1)
                    .map(line -> line.split(","))
                    .collect(groupingBy(array -> array[USER_REGION], groupingBy(array -> array[USER_ID], counting())));

            collect.entrySet().stream()
                    .map(e -> Map.entry(
                            e.getKey(),
                            //获取前三的值
//                            e.getValue().entrySet().stream()
//                                    .sorted(Map.Entry.<String,Long>comparingByValue().reversed())
//                                    .limit(3)
//                                    .collect(toList())
                            e.getValue().entrySet().stream()
                                    .collect(
                                            () -> new MyQueue<Map.Entry<String,Long>>(Map.Entry.comparingByValue(),3),
                                            MyQueue::offer,
                                            MyQueue::addAll
                                    )
                    ))
                    .forEach(System.out::println);

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 4.1) 求下单最多的前10名用户 --- 堆实现
    //继承小顶堆类
    static class MyQueue<E> extends PriorityQueue<E>{
        private int max;

        public MyQueue(Comparator<? super E>comparator,int max){
            super(comparator);
            this.max = max;
        }

        @Override
        public boolean offer(E e) {
            boolean r = super.offer(e);
            if (this.size() > max){
                this.poll();
            }
            return r;
        }
    }
    private static void case41(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<String, Long> collect = lines.skip(1)
                    .map(line -> line.split(","))
                    .collect(groupingBy(array -> array[USER_ID], counting()));

            //小顶堆实现
            MyQueue<Map.Entry<String, Long>> queue = collect.entrySet().stream()
                    .collect(
                            () -> new MyQueue<Map.Entry<String, Long>>(Map.Entry.comparingByValue(), 10),
                            (q, x) -> q.offer(x),
                            (q1, q2) -> q1.addAll(q2)
                    );
            while (!queue.isEmpty()) {
                System.out.println(queue.poll());
            }

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 4.2) 求下单最多的前10名用户 --- 排序实现
    private static void case42(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            lines.skip(1)
                    .map(line -> line.split(","))
                    .collect(groupingBy(array -> array[USER_ID],counting()))
                    .entrySet().stream()
                    .sorted(Map.Entry.<String,Long>comparingByValue().reversed()) // 根据值进行倒叙排序(重要)
                    .limit(10)
                    .forEach(System.out::println);

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }
    // 3) 统计最高销量的商品
    private static void case3(){
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) { //.twr(快捷键) --- 保证流最终会被close关闭
            lines.skip(1)
                    .map(line -> line.split(","))
                    .collect(groupingBy(array -> array[PRODUCT_ID],counting()))
                    .entrySet().stream() // 将map变成流 重要
                    .max(Map.Entry.comparingByValue()) // 根据值比较最大
                    .ifPresent(System.out::println);
        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    // 2) 统计销售量最高的月份
    private static void case2(){
        try(Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
               lines.skip(1)
//                    .limit(5)
                    .map(line -> line.split(","))
                    .collect(groupingBy(array -> YearMonth.from(formatter.parse(array[TIME])), counting()))
                    .entrySet().stream()
//                    .max(Comparator.comparing(e -> e.getValue()))
                    .max(Map.Entry.comparingByValue()) // 根据值比较
                    .ifPresent(x -> System.out.println(x));

        }catch (IOException e){
            throw new RuntimeException(e);
        }

    }
    // 1) 统计每月的销售量
    private static void case1() {
        try (Stream<String> lines = Files.lines(Path.of(DATA_URL))) {
            Map<YearMonth, Long> collect = lines.skip(1)
                    .map(line -> line.split(",")) // 以逗号截取数据
                    .collect(groupingBy(array -> YearMonth.from(formatter.parse(array[TIME])), TreeMap::new, counting()));
            for (Map.Entry<YearMonth, Long> e : collect.entrySet()) {
                System.out.println(e);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
